#include "Socket.hpp"
#include <sys/epoll.h>

using namespace socket_ns;

class EpollServer
{
    const static int N = 64;
    const static int Buffer_Size = 1024;

private:
    uint16_t _port;
    unique_ptr<Socket> _listensock;

    int epollfd;
    struct epoll_event _events[N];

public:
    EpollServer(uint16_t port = 8080)
        : _port(port), _listensock(make_unique<TcpSocket>())
    {
        Analyze an("0", _port);
        _listensock->BuildTcpServerSocket(an);

        epollfd = epoll_create(128);
        if (epollfd < 0)
        {
            Log(Error, "epoll create fail");
            exit(1);
        }

        struct epoll_event event;
        event.events = EPOLLIN;
        event.data.fd = _listensock->getfd();
        epoll_ctl(epollfd, EPOLL_CTL_ADD, _listensock->getfd(), &event);
    }

    ~EpollServer()
    {
        epoll_ctl(epollfd, EPOLL_CTL_DEL, _listensock->getfd(), nullptr);
        close(_listensock->getfd());

        if (epollfd > 0)
            close(epollfd);
    }

    void Loop()
    {
        while (true)
        {
            int timeout = 1000; // 正数等待时间，0为非阻塞，负数为阻塞
            int n = epoll_wait(epollfd, _events, N, timeout);
            switch (n)
            {
            case 0:
                Log(Info, "timeout...");
                break;
            case -1:
                Log(Error, "epoll wait error");
                break;
            default:
                Log(Info, "epoll wait success");
                Handler(n);
                break;
            }
        }
    }

    void Handler(int num)
    {
        cout << "num : " << num << endl;
        for (int i = 0; i < num; i++)
        {
            int events = _events[i].events;
            int fd = _events[i].data.fd;

            if (events & EPOLLIN)
            {
                if (fd == _listensock->getfd())
                {
                    Analyze an;
                    sock_addr norfd = _listensock->Accept(an);

                    struct epoll_event event;
                    event.events = EPOLLIN;
                    event.data.fd = norfd->getfd();
                    epoll_ctl(epollfd, EPOLL_CTL_ADD, norfd->getfd(), &event);
                }
                else
                {
                    char buffer[Buffer_Size];
                    int n = recv(fd, buffer, Buffer_Size, 0);
                    if(n > 0)
                    {
                        string res = "server: ";
                        res += buffer;

                        send(fd, res.c_str(), res.size(), 0);
                    }
                    else if(n == 0)
                    {
                        Log(Info, "User quit");
                        epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, nullptr);
                        close(fd);
                    }
                    else 
                    {
                        Log(Error, "recv error");
                        epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, nullptr);
                        close(fd);
                    }
                }
            }
        }
    }
};